package org.jkuang.qstar.commons.io;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Arrays;

/**
 * 
 * @author jkuang
 * 
 */
public class ByteWriter {
	private int size;
	private byte[] buffer;
	static final Charset CHARSET = Charset.forName("utf8");

	public ByteWriter(int size) {
		this.buffer = new byte[size];
	}

	public int size() {
		return this.size;
	}

	public void ensureCapacity(int minCapacity) {
		int oldCapacity = buffer.length;
		if (minCapacity > oldCapacity) {
			int newCapacity = (oldCapacity * 3) / 2 + 1;
			if (newCapacity < minCapacity) {
				newCapacity = minCapacity;
			}
			buffer = Arrays.copyOf(buffer, newCapacity);
		}
	}

	public void reset() {
		this.size = 0;
	}

	public byte[] array() {
		return this.buffer;
	}

	public byte[] toByteArray() {
		byte[] bs = new byte[size];
		System.arraycopy(buffer, 0, bs, 0, bs.length);
		return bs;
	}

	public static void main(String[] arg) {
		byte[] array = new byte[1024 * 1024];
		byte[] array0 = new byte[1024 * 10];
		for (int i = 0; i < 10000; i++) {
			for (int j = 0; j < array0.length; j++) {
				array0[j] = array[j];
			}
		}
	}

	public void writeInt(int i) {
		writeByte((byte) (i >> 24));
		writeByte((byte) (i >> 16));
		writeByte((byte) (i >> 8));
		writeByte((byte) i);
	}

	public int readInt(byte[] bs, int pos) {
		return bs[pos++] << 24 | bs[pos++] << 16 | bs[pos++] << 8 | bs[pos++];
	}

	public void writeShort(short i) {
		writeByte((byte) (i >> 8));
		writeByte((byte) i);
	}

	public void writeChar(char i) {
		writeByte((byte) (i >> 8));
		writeByte((byte) i);
	}

	public void writeByte(byte value) {
		ensureCapacity(size + 1);
		buffer[size++] = value;
	}

	public void writeByte(byte[] value) {
		if (value == null || value.length == 0) {
			return;
		}
		writeByte(value, 0, value.length);
	}

	public void writeByte(byte[] src, int srcPos, int length) {
		ensureCapacity(size + length);
		if (length > 128) {

			System.arraycopy(src, srcPos, buffer, size, length);
		} else {
			for (int i = 0; i < length; i++) {
				buffer[size + i] = src[srcPos + i];
			}
		}
		size += length;
	}

	public void writeShortString(String value) {
		if (value == null) {
			writeShort((short) 0);

		} else {
			byte[] data = value.getBytes(CHARSET);
			writeShort((short) data.length);
			writeByte(data);
		}

	}

	public void writeIntString(String value) {
		if (value == null) {
			writeInt(0);
		} else {

			byte[] data = value.getBytes(CHARSET);
			writeInt(data.length);
			writeByte(data);
		}
	}

	public void writeShortBytes(byte[] value) {
		if (value == null) {
			writeShort((short) 0);

		} else {
			writeShort((short) value.length);
			writeByte(value);
		}

	}

	public void writeIntBytes(byte[] value) {
		if (value == null) {
			writeInt(0);
		} else {
			writeInt(value.length);
			writeByte(value);
		}
	}

	public final void writeVInt(int i) throws IOException {
		while ((i & ~0x7F) != 0) {
			writeByte((byte) ((i & 0x7F) | 0x80));
			i >>>= 7;
		}
		writeByte((byte) i);
	}

	public void writeLong(long i) {
		writeInt((int) (i >> 32));
		writeInt((int) i);
	}

	public final void writeVLong(long i) throws IOException {
		assert i >= 0L;
		while ((i & ~0x7FL) != 0L) {
			writeByte((byte) ((i & 0x7FL) | 0x80L));
			i >>>= 7;
		}
		writeByte((byte) i);
	}

	public static byte[] write(int val) {
		byte[] bs = new byte[4];
		bs[0] = (byte) (val >> 24);
		bs[1] = (byte) (val >> 16);
		bs[2] = (byte) (val >> 8);
		bs[3] = (byte) val;
		return bs;
	}

	public static byte[] write(long val) {
		byte[] bs = new byte[8];
		bs[0] = (byte) (val >> 56);
		bs[1] = (byte) (val >> 48);
		bs[2] = (byte) (val >> 40);
		bs[3] = (byte) (val >> 32);
		bs[4] = (byte) (val >> 24);
		bs[5] = (byte) (val >> 16);
		bs[6] = (byte) (val >> 8);
		bs[7] = (byte) val;
		return bs;
	}

}
